package com.yss.sofa.report.engine.util;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.RenderingHints;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.PieToolTipGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieToolTipGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.DatasetRenderingOrder;
import org.jfree.chart.plot.PieLabelLinkStyle;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.RingPlot;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.category.StackedAreaRenderer;
import org.jfree.chart.renderer.category.StackedBarRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.chart.urls.PieURLGenerator;
import org.jfree.chart.urls.StandardPieURLGenerator;
import org.jfree.chart.util.ParamChecks;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.ui.RectangleEdge;
import org.jfree.util.TableOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.yss.sofa.framework.services.ServiceFactory;
import com.yss.sofa.framework.services.report.ReportCustomImage;
import com.yss.sofa.report.engine.DataSetData;
import com.yss.sofa.report.engine.cell.visible.result.ChartResultCell;
import com.yss.sofa.report.engine.cell.visible.result.FloatingResultCell;
import com.yss.sofa.report.engine.jfree.MultiplePiePlot2;
import com.yss.sofa.report.engine.jfree.SpiderWebPlot2;
import com.yss.sofa.report.engine.series.BarLineSeries;
import com.yss.sofa.report.engine.series.CustomSeries;
import com.yss.sofa.report.engine.series.MultiPieSeries;
import com.yss.sofa.report.engine.series.NormalBarSeries;
import com.yss.sofa.report.engine.series.NormalLineSeries;
import com.yss.sofa.report.engine.series.NormalPieSeries;
import com.yss.sofa.report.engine.series.Series;
import com.yss.sofa.report.engine.series.SpiderWebSeries;
import com.yss.sofa.report.engine.series.StackAreaSeries;
import com.yss.sofa.report.engine.series.StackBarSeries;

public final class ChartUtil {
	private static final Logger LOGGER=LoggerFactory.getLogger(ChartUtil.class);
	static {
		StandardChartTheme theme = new StandardChartTheme("com.yss.sofa.report.engine");
		theme.setExtraLargeFont(new Font("SansSerif", Font.PLAIN, 16));  
		theme.setLargeFont(new Font("SansSerif", Font.PLAIN, 14));  
		theme.setRegularFont(new Font("SansSerif", Font.PLAIN, 12));  
		theme.setSmallFont(new Font("SansSerif", Font.PLAIN, 10));  
		ChartFactory.setChartTheme(theme);
	}
	public static byte[] generateFloatingPNG(FloatingResultCell cell,int width,int height,Map<String, Serializable> paramsmap,Map<String,String> consts) throws Exception{
		String clazz=cell.getFloating().getClazz();
		Set<String> params=cell.getFloating().getParams();
		try {
			Map<String,String> filter=new HashMap<String, String>();
			filter.put("class", clazz);
			ReportCustomImage image=ServiceFactory.getInstance().getService(ReportCustomImage.class,filter);
			Map<String,Serializable> values=new HashMap<String, Serializable>();
			for(String key:params){
				values.put(key, paramsmap.get(key));
			}
			values.put("CONSTS", (HashMap<String, String>)consts);
			LOGGER.info("调用报表自定义图形["+image.getClass().getCanonicalName()+"]");
			byte[] png=image.generatePng(width, height, values);
			if(png==null){
				throw new Exception("OSGI服务["+clazz+"]的返回结果为null");
			}
			return png;
		} catch (Exception e) {
			throw new Exception("OSGI服务["+clazz+"]执行失败",e);
		}
	}
	private static byte[] generateCustom(CustomSeries series,int width,int height,Map<String, Serializable> paramsmap,Map<String,String> consts,Map<String,String> record) throws Exception{
		String clazz=series.getClazz();
		Set<String> params=series.getParams();
		try {
			Map<String,String> filter=new HashMap<String, String>();
			filter.put("class", clazz);
			ReportCustomImage image=ServiceFactory.getInstance().getService(ReportCustomImage.class,filter);
			Map<String,Serializable> values=new HashMap<String, Serializable>();
			for(String p:params){
				values.put(p, paramsmap.get(p));
			}
			HashMap<String, String> data=new HashMap<String, String>();
			data.putAll(record);
			values.put("DATA", data);
			values.put("CONSTS", (HashMap<String, String>)consts);
			LOGGER.info("调用报表自定义图形["+image.getClass().getCanonicalName()+"]");
			byte[] png=image.generatePng(width, height, values);
			if(png==null){
				throw new Exception("OSGI服务["+clazz+"]的返回结果为null");
			}
			return png;
		} catch (Exception e) {
			throw new Exception("自定义图形["+clazz+"]执行失败",e);
		}
	}
	private static JFreeChart createSpiderWebChart(String title, CategoryDataset dataset, boolean legend, boolean tooltips, boolean urls){
		SpiderWebPlot2 plot = new SpiderWebPlot2(dataset);
		//TODO: 初始化
		JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT,
                plot, legend);
        ChartFactory.getChartTheme().apply(chart);
        return chart;
	}
	private static byte[] generateSpiderWebSeries(SpiderWebSeries series,int width,int height,DataSetData data) throws Exception{
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		int count=data.getCount();
		for(int i=0;i<count;i++){
			String category=data.getValue(i, series.getCategory());
			String item=data.getValue(i, series.getItem());
			String value=data.getValue(i, series.getValue());
			if(series.isIgnoreEmptyCategory() && StringUtils.isEmpty(category)){
				continue;
			}
			if(series.isIgnoreEmptyItem() && StringUtils.isEmpty(item)){
				continue;
			}
			if(series.isIgnoreEmptyValue() && StringUtils.isEmpty(value)){
				continue;
			}
			dataset.setValue(Double.valueOf(value), item, category);
		}
		JFreeChart chart=createSpiderWebChart(null, dataset,series.isLegend(),false,false);
		chart.getRenderingHints().put (RenderingHints.KEY_TEXT_ANTIALIASING,series.isAntialias()?RenderingHints.VALUE_TEXT_ANTIALIAS_ON:RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
		chart.setBackgroundPaint(null);
		chart.setBorderPaint(null);
		if(series.isLegend()){
			chart.getLegend().setBackgroundPaint(Color.WHITE);
			switch (series.getLegendPosition()) {
			case 0:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			case 1:
				chart.getLegend().setPosition(RectangleEdge.RIGHT);
				break;
			case 2:
				chart.getLegend().setPosition(RectangleEdge.TOP);
				break;
			case 3:
				chart.getLegend().setPosition(RectangleEdge.LEFT);
				break;
			default:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			}
		}
		SpiderWebPlot2 plot = (SpiderWebPlot2)chart.getPlot();
		plot.setNoDataMessage("<无数据>");
		plot.setBackgroundPaint(null);
		plot.setAxisLinePaint(Color.lightGray);
		plot.setSeriesOutlineStroke(new BasicStroke(series.getLineWidth()));
		plot.setWebFilled(series.isFill());
		if(series.getMax()>0){
			plot.setMaxValue(series.getMax());
		}
		chart.getPlot().setOutlineVisible(series.isOutline());

		if(series.getColors()!=null && !series.getColors().isEmpty()){
			int datacount=dataset.getRowCount();
			int colorcount=series.getColors().size();
			for(int i=0;i<datacount;i++){
				int colorindex=i%colorcount;
				plot.setSeriesPaint(i, Color.decode(series.getColors().get(colorindex)));
			}
		}
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		ChartUtilities.writeChartAsPNG(out, chart, width, height);
		return out.toByteArray();
	}

	private static byte[] generateNormalPieSeries(NormalPieSeries series,int width,int height,DataSetData data) throws Exception{
		DefaultPieDataset dataset = new DefaultPieDataset();
		int count=data.getCount();
		for(int i=0;i<count;i++){
			String key=data.getValue(i, series.getKey());
			String value=data.getValue(i, series.getValue());
			if(series.isIgnoreEmptyKey() && StringUtils.isEmpty(key)){
				continue;
			}
			if(series.isIgnoreEmptyValue() && StringUtils.isEmpty(value)){
				continue;
			}
			dataset.setValue(key,Double.valueOf(value));
		}
		JFreeChart chart;
		if(series.isRing()){
			chart=ChartFactory.createRingChart(null, dataset,series.isLegend(),false,false);
		} else {
			chart=ChartFactory.createPieChart(null, dataset,series.isLegend(),false,false);
		}
		
		chart.getRenderingHints().put (RenderingHints.KEY_TEXT_ANTIALIASING,series.isAntialias()?RenderingHints.VALUE_TEXT_ANTIALIAS_ON:RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
		chart.setBackgroundPaint(null);
		chart.setBorderPaint(null);
		if(series.isLegend()){
			chart.getLegend().setBackgroundPaint(Color.WHITE);
			switch (series.getLegendPosition()) {
			case 0:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			case 1:
				chart.getLegend().setPosition(RectangleEdge.RIGHT);
				break;
			case 2:
				chart.getLegend().setPosition(RectangleEdge.TOP);
				break;
			case 3:
				chart.getLegend().setPosition(RectangleEdge.LEFT);
				break;
			default:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			}
		}
		PiePlot plot = (PiePlot)chart.getPlot();
		plot.setNoDataMessage("<无数据>");
		plot.setBackgroundPaint(null);
		plot.setShadowPaint(null);
		plot.setOutlineVisible(series.isOutline());
		plot.setCircular(series.isCircular());
		if(StringUtils.isNotEmpty(series.getExplode())){
			plot.setExplodePercent(series.getExplode(), 0.2);
		}
		if(StringUtils.isNotEmpty(series.getLabel())){
			plot.setLabelGenerator(new StandardPieSectionLabelGenerator(series.getLabel()));
			plot.setLabelBackgroundPaint(null);
			plot.setLabelShadowPaint(null);
			plot.setLabelOutlinePaint(null);
			plot.setLabelLinkStyle(PieLabelLinkStyle.STANDARD);
		} else {
			plot.setLabelGenerator(null);
		}
		if(series.getColors()!=null && !series.getColors().isEmpty()){
			int datacount=dataset.getItemCount();
			int colorcount=series.getColors().size();
			for(int i=0;i<datacount;i++){
				int colorindex=i%colorcount;
				plot.setSectionPaint(dataset.getKey(i), Color.decode(series.getColors().get(colorindex)));
			}
		}
		if(series.isRing()){
			RingPlot rp=(RingPlot)plot;
			rp.setSectionDepth(series.getDepth());
			rp.setSeparatorsVisible(false);
		}
		plot.setSectionOutlinesVisible(false);
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		ChartUtilities.writeChartAsPNG(out, chart, width, height);
		return out.toByteArray();
	}

	private static JFreeChart createMultiplePieChart(String title,
            CategoryDataset dataset, TableOrder order, boolean legend,
            boolean tooltips, boolean urls, boolean ring, int colCount){

        ParamChecks.nullNotPermitted(order, "order");
        MultiplePiePlot2 plot = new MultiplePiePlot2(dataset,ring,colCount);
        plot.setDataExtractOrder(order);
        plot.setBackgroundPaint(null);
        plot.setOutlineStroke(null);

        if (tooltips) {
            PieToolTipGenerator tooltipGenerator
                = new StandardPieToolTipGenerator();
            PiePlot pp = (PiePlot) plot.getPieChart().getPlot();
            pp.setToolTipGenerator(tooltipGenerator);
        }

        if (urls) {
            PieURLGenerator urlGenerator = new StandardPieURLGenerator();
            PiePlot pp = (PiePlot) plot.getPieChart().getPlot();
            pp.setURLGenerator(urlGenerator);
        }

        JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT,
                plot, legend);
        ChartFactory.getChartTheme().apply(chart);
        return chart;

    }

	private static byte[] generateMultiPieSeries(MultiPieSeries series,int width,int height,DataSetData data) throws Exception{
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		int count=data.getCount();
		for(int i=0;i<count;i++){
			String category=data.getValue(i, series.getCategory());
			String item=data.getValue(i, series.getItem());
			String value=data.getValue(i, series.getValue());
			if(series.isIgnoreEmptyCategory() && StringUtils.isEmpty(category)){
				continue;
			}
			if(series.isIgnoreEmptyItem() && StringUtils.isEmpty(item)){
				continue;
			}
			if(series.isIgnoreEmptyValue() && StringUtils.isEmpty(value)){
				continue;
			}
			dataset.setValue(Double.valueOf(value), item, category);
		}
		JFreeChart chart=/*ChartFactory.*/createMultiplePieChart(null, dataset, TableOrder.BY_ROW, series.isLegend(), false, false, series.isRing(), series.getColCount());
		chart.getRenderingHints().put (RenderingHints.KEY_TEXT_ANTIALIASING,series.isAntialias()?RenderingHints.VALUE_TEXT_ANTIALIAS_ON:RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
		chart.setBackgroundPaint(null);
		chart.setBorderPaint(null);
		if(series.isLegend()){
			chart.getLegend().setBackgroundPaint(Color.WHITE);
			switch (series.getLegendPosition()) {
			case 0:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			case 1:
				chart.getLegend().setPosition(RectangleEdge.RIGHT);
				break;
			case 2:
				chart.getLegend().setPosition(RectangleEdge.TOP);
				break;
			case 3:
				chart.getLegend().setPosition(RectangleEdge.LEFT);
				break;
			default:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			}
		}
		MultiplePiePlot2 _ = (MultiplePiePlot2)chart.getPlot();
		_.setNoDataMessage("<无数据>");
		_.setBackgroundPaint(null);
		_.setOutlineVisible(false);
		JFreeChart pie=_.getPieChart();
		PiePlot plot = (PiePlot)pie.getPlot();
		plot.setNoDataMessage("<无数据>");
		plot.setBackgroundPaint(null);
		plot.setShadowPaint(null);
		plot.setOutlineVisible(series.isOutline());
		plot.setCircular(series.isCircular());
		if(StringUtils.isNotEmpty(series.getExplode())){
			plot.setExplodePercent(series.getExplode(), 0.2);
		}
		if(StringUtils.isNotEmpty(series.getLabel())){
			plot.setLabelGenerator(new StandardPieSectionLabelGenerator(series.getLabel()));
			plot.setLabelBackgroundPaint(null);
			plot.setLabelShadowPaint(null);
			plot.setLabelOutlinePaint(null);
			plot.setLabelLinkStyle(PieLabelLinkStyle.STANDARD);
		} else {
			plot.setLabelGenerator(null);
		}
		if(series.getColors()!=null && !series.getColors().isEmpty()){
			int datacount=dataset.getColumnCount();
			int colorcount=series.getColors().size();
			for(int i=0;i<datacount;i++){
				int colorindex=i%colorcount;
				plot.setSectionPaint(dataset.getColumnKey(i), Color.decode(series.getColors().get(colorindex)));
			}
		}
		if(series.isRing()){
			RingPlot rp=(RingPlot)plot;
			rp.setSectionDepth(series.getDepth());
			rp.setSeparatorsVisible(false);
		}
		plot.setSectionOutlinesVisible(false);
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		ChartUtilities.writeChartAsPNG(out, chart, width, height);
		return out.toByteArray();
	}

	private static byte[] generateNormalBarSeries(NormalBarSeries series,int width,int height,DataSetData data) throws Exception{
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		int count=data.getCount();
		for(int i=0;i<count;i++){
			String category=data.getValue(i, series.getCategory());
			String item=data.getValue(i, series.getItem());
			String value=data.getValue(i, series.getValue());
			if(series.isIgnoreEmptyCategory() && StringUtils.isEmpty(category)){
				continue;
			}
			if(series.isIgnoreEmptyItem() && StringUtils.isEmpty(item)){
				continue;
			}
			if(series.isIgnoreEmptyValue() && StringUtils.isEmpty(value)){
				continue;
			}
			dataset.setValue(Double.valueOf(value), item, category);
		}
		JFreeChart chart=ChartFactory.createBarChart(null, series.getCategoryAxisLabel(),series.getValueAxisLabel(), dataset,series.isHorizontal()?PlotOrientation.HORIZONTAL:PlotOrientation.VERTICAL,series.isLegend(),false,false);
		chart.getRenderingHints().put (RenderingHints.KEY_TEXT_ANTIALIASING,series.isAntialias()?RenderingHints.VALUE_TEXT_ANTIALIAS_ON:RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
		chart.setBackgroundPaint(null);
		chart.setBorderPaint(null);
		if(series.isLegend()){
			chart.getLegend().setBackgroundPaint(Color.WHITE);
			switch (series.getLegendPosition()) {
			case 0:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			case 1:
				chart.getLegend().setPosition(RectangleEdge.RIGHT);
				break;
			case 2:
				chart.getLegend().setPosition(RectangleEdge.TOP);
				break;
			case 3:
				chart.getLegend().setPosition(RectangleEdge.LEFT);
				break;
			default:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			}
		}
		CategoryPlot plot = (CategoryPlot)chart.getPlot();
		plot.setNoDataMessage("<无数据>");
		plot.setBackgroundPaint(null);
		plot.setRangeGridlinePaint(Color.lightGray);
		plot.setRangeGridlinesVisible(series.isGridline());
		chart.getPlot().setOutlineVisible(series.isOutline());
		BarRenderer renderer=(BarRenderer)plot.getRenderer();
		renderer.setBarPainter(new StandardBarPainter());
		if(series.getColors()!=null && !series.getColors().isEmpty()){
			int datacount=dataset.getRowCount();
			int colorcount=series.getColors().size();
			for(int i=0;i<datacount;i++){
				int colorindex=i%colorcount;
				renderer.setSeriesPaint(i, Color.decode(series.getColors().get(colorindex)));
			}
		}
		if(series.getMaxBarWidth()>0 && series.getMaxBarWidth()<1){
			renderer.setMaximumBarWidth(series.getMaxBarWidth());
		}
		switch (series.getTickX()) {
		case 0:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
			break;
		case 1:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_45);
			break;
		case 2:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
			break;
		default:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
			break;
		}
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		ChartUtilities.writeChartAsPNG(out, chart, width, height);
		return out.toByteArray();
	}
	
	private static byte[] generateStackBarSeries(StackBarSeries series,int width,int height,DataSetData data) throws Exception{
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		int count=data.getCount();
		for(int i=0;i<count;i++){
			String category=data.getValue(i, series.getCategory());
			String item=data.getValue(i, series.getItem());
			String value=data.getValue(i, series.getValue());
			if(series.isIgnoreEmptyCategory() && StringUtils.isEmpty(category)){
				continue;
			}
			if(series.isIgnoreEmptyItem() && StringUtils.isEmpty(item)){
				continue;
			}
			if(series.isIgnoreEmptyValue() && StringUtils.isEmpty(value)){
				continue;
			}
			dataset.setValue(Double.valueOf(value), item, category);
		}
		JFreeChart chart=ChartFactory.createStackedBarChart(null, series.getCategoryAxisLabel(),series.getValueAxisLabel(), dataset,series.isHorizontal()?PlotOrientation.HORIZONTAL:PlotOrientation.VERTICAL,series.isLegend(),false,false);
		chart.getRenderingHints().put (RenderingHints.KEY_TEXT_ANTIALIASING,series.isAntialias()?RenderingHints.VALUE_TEXT_ANTIALIAS_ON:RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
		chart.setBackgroundPaint(null);
		chart.setBorderPaint(null);
		if(series.isLegend()){
			chart.getLegend().setBackgroundPaint(Color.WHITE);
			switch (series.getLegendPosition()) {
			case 0:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			case 1:
				chart.getLegend().setPosition(RectangleEdge.RIGHT);
				break;
			case 2:
				chart.getLegend().setPosition(RectangleEdge.TOP);
				break;
			case 3:
				chart.getLegend().setPosition(RectangleEdge.LEFT);
				break;
			default:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			}
		}
		CategoryPlot plot = (CategoryPlot)chart.getPlot();
		plot.setNoDataMessage("<无数据>");
		plot.setBackgroundPaint(null);
		plot.setRangeGridlinePaint(Color.lightGray);
		plot.setRangeGridlinesVisible(series.isGridline());
		chart.getPlot().setOutlineVisible(series.isOutline());
		StackedBarRenderer renderer=(StackedBarRenderer)plot.getRenderer();
		renderer.setBarPainter(new StandardBarPainter());
		if(series.isPercent()){
			((NumberAxis)plot.getRangeAxis()).setNumberFormatOverride(NumberFormat.getPercentInstance());
			renderer.setRenderAsPercentages(true);
		}
		
		if(series.getColors()!=null && !series.getColors().isEmpty()){
			int datacount=dataset.getRowCount();
			int colorcount=series.getColors().size();
			for(int i=0;i<datacount;i++){
				int colorindex=i%colorcount;
				renderer.setSeriesPaint(i, Color.decode(series.getColors().get(colorindex)));
			}
		}
		if(series.getMaxBarWidth()>0 && series.getMaxBarWidth()<1){
			renderer.setMaximumBarWidth(series.getMaxBarWidth());
		}
		switch (series.getTickX()) {
		case 0:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
			break;
		case 1:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_45);
			break;
		case 2:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
			break;
		default:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
			break;
		}
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		ChartUtilities.writeChartAsPNG(out, chart, width, height);
		return out.toByteArray();
	}
	
	private static byte[] generateStackAreaSeries(StackAreaSeries series,int width,int height,DataSetData data) throws Exception{
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		int count=data.getCount();
		for(int i=0;i<count;i++){
			String category=data.getValue(i, series.getCategory());
			String item=data.getValue(i, series.getItem());
			String value=data.getValue(i, series.getValue());
			if(series.isIgnoreEmptyCategory() && StringUtils.isEmpty(category)){
				continue;
			}
			if(series.isIgnoreEmptyItem() && StringUtils.isEmpty(item)){
				continue;
			}
			if(series.isIgnoreEmptyValue() && StringUtils.isEmpty(value)){
				continue;
			}
			dataset.setValue(Double.valueOf(value), item, category);
		}
		JFreeChart chart=ChartFactory.createStackedAreaChart(null, series.getCategoryAxisLabel(),series.getValueAxisLabel(), dataset,series.isHorizontal()?PlotOrientation.HORIZONTAL:PlotOrientation.VERTICAL,series.isLegend(),false,false);
		chart.getRenderingHints().put (RenderingHints.KEY_TEXT_ANTIALIASING,series.isAntialias()?RenderingHints.VALUE_TEXT_ANTIALIAS_ON:RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
		chart.setBackgroundPaint(null);
		chart.setBorderPaint(null);
		if(series.isLegend()){
			chart.getLegend().setBackgroundPaint(Color.WHITE);
			switch (series.getLegendPosition()) {
			case 0:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			case 1:
				chart.getLegend().setPosition(RectangleEdge.RIGHT);
				break;
			case 2:
				chart.getLegend().setPosition(RectangleEdge.TOP);
				break;
			case 3:
				chart.getLegend().setPosition(RectangleEdge.LEFT);
				break;
			default:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			}
		}
		CategoryPlot plot = (CategoryPlot)chart.getPlot();
		plot.setNoDataMessage("<无数据>");
		plot.setBackgroundPaint(null);
		plot.setRangeGridlinePaint(Color.lightGray);
		plot.setRangeGridlinesVisible(series.isGridline());
		chart.getPlot().setOutlineVisible(series.isOutline());
		StackedAreaRenderer renderer=(StackedAreaRenderer)plot.getRenderer();
		if(series.isPercent()){
			((NumberAxis)plot.getRangeAxis()).setNumberFormatOverride(NumberFormat.getPercentInstance());
			renderer.setRenderAsPercentages(true);
		}
		if(series.getColors()!=null && !series.getColors().isEmpty()){
			int datacount=dataset.getRowCount();
			int colorcount=series.getColors().size();
			for(int i=0;i<datacount;i++){
				int colorindex=i%colorcount;
				renderer.setSeriesPaint(i, Color.decode(series.getColors().get(colorindex)));
			}
		}
		switch (series.getTickX()) {
		case 0:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
			break;
		case 1:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_45);
			break;
		case 2:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
			break;
		default:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
			break;
		}
//		plot.getDomainAxis().setLowerMargin(0);
//		plot.getDomainAxis().setUpperMargin(0);
//		plot.getDomainAxis().setCategoryMargin(0);
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		ChartUtilities.writeChartAsPNG(out, chart, width, height);
		return out.toByteArray();
	}
	
	private static byte[] generateBarLineSeries(BarLineSeries series,int width,int height,DataSetData data) throws Exception{
		int count=data.getCount();
		DefaultCategoryDataset bardataset = new DefaultCategoryDataset();
		for(int i=0;i<count;i++){
			String category=data.getValue(i, series.getCategory());
			String item=data.getValue(i, series.getBarItem());
			String value=data.getValue(i, series.getBarValue());
			if(series.isIgnoreEmptyCategory() && StringUtils.isEmpty(category)){
				continue;
			}
			if(series.isIgnoreEmptyBarItem() && StringUtils.isEmpty(item)){
				continue;
			}
			if(series.isIgnoreEmptyBarValue() && StringUtils.isEmpty(value)){
				continue;
			}
			bardataset.setValue(Double.valueOf(value), item, category);
		}
		DefaultCategoryDataset linedataset = new DefaultCategoryDataset();
		for(int i=0;i<count;i++){
			String category=data.getValue(i, series.getCategory());
			String item=data.getValue(i, series.getLineItem());
			String value=data.getValue(i, series.getLineValue());
			if(series.isIgnoreEmptyCategory() && StringUtils.isEmpty(category)){
				continue;
			}
			if(series.isIgnoreEmptyLineItem() && StringUtils.isEmpty(item)){
				continue;
			}
			if(series.isIgnoreEmptyLineValue() && StringUtils.isEmpty(value)){
				continue;
			}
			linedataset.setValue(Double.valueOf(value), item, category);
		}
		JFreeChart chart=ChartFactory.createBarChart(null, series.getCategoryAxisLabel(),series.getBarValueAxisLabel(), bardataset,series.isHorizontal()?PlotOrientation.HORIZONTAL:PlotOrientation.VERTICAL,series.isLegend(),false,false);
		
		if(series.isLegend()){
			chart.getLegend().setBackgroundPaint(Color.WHITE);
			switch (series.getLegendPosition()) {
			case 0:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			case 1:
				chart.getLegend().setPosition(RectangleEdge.RIGHT);
				break;
			case 2:
				chart.getLegend().setPosition(RectangleEdge.TOP);
				break;
			case 3:
				chart.getLegend().setPosition(RectangleEdge.LEFT);
				break;
			default:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			}
		}
		CategoryPlot plot = (CategoryPlot)chart.getPlot();
		plot.setDataset(1, linedataset);
		plot.mapDatasetToRangeAxis(1, 1);
		NumberAxis numberaxis = new NumberAxis(series.getLineValueAxisLabel());
		plot.setRangeAxis(1, numberaxis);
		ChartFactory.getChartTheme().apply(chart);
		chart.getRenderingHints().put (RenderingHints.KEY_TEXT_ANTIALIASING,series.isAntialias()?RenderingHints.VALUE_TEXT_ANTIALIAS_ON:RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
		chart.setBackgroundPaint(null);
		chart.setBorderPaint(null);
		plot.setNoDataMessage("<无数据>");
		plot.setBackgroundPaint(null);
		plot.setRangeGridlinePaint(Color.lightGray);
		plot.setRangeGridlinesVisible(series.isGridline());
		plot.setOutlineVisible(series.isOutline());
		//bar begin
		BarRenderer barrenderer=(BarRenderer)plot.getRenderer(0);
		barrenderer.setBarPainter(new StandardBarPainter());
		if(series.getBarColors()!=null && !series.getBarColors().isEmpty()){
			int datacount=bardataset.getRowCount();
			int colorcount=series.getBarColors().size();
			for(int i=0;i<datacount;i++){
				int colorindex=i%colorcount;
				barrenderer.setSeriesPaint(i, Color.decode(series.getBarColors().get(colorindex)));
			}
		}
		if(series.getMaxBarWidth()>0 && series.getMaxBarWidth()<1){
			barrenderer.setMaximumBarWidth(series.getMaxBarWidth());
		}
		//bar end
		//line begin
		LineAndShapeRenderer linerenderer = new LineAndShapeRenderer();
		plot.setRenderer(1, linerenderer);
		plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
		linerenderer.setBaseShapesVisible(series.isShape());
		linerenderer.setUseFillPaint(true);
		int seriesCount=linedataset.getRowCount();
		for(int i=0;i<seriesCount;i++){
			linerenderer.setSeriesStroke(i, new BasicStroke(series.getLineWidth()));
			linerenderer.setSeriesOutlineStroke(i, new BasicStroke(series.getLineWidth()));
		}
		if(series.getLineColors()!=null && !series.getLineColors().isEmpty()){
			int colorcount=series.getLineColors().size();
			for(int i=0;i<seriesCount;i++){
				int colorindex=i%colorcount;
				linerenderer.setSeriesPaint(i, Color.decode(series.getLineColors().get(colorindex)));
			}
		}
		//line end
		switch (series.getTickX()) {
		case 0:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
			break;
		case 1:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_45);
			break;
		case 2:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
			break;
		default:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
			break;
		}
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		ChartUtilities.writeChartAsPNG(out, chart, width, height);
		return out.toByteArray();
	}

	private static byte[] generateNormalLineSeries(NormalLineSeries series,int width,int height,DataSetData data) throws Exception{
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		int count=data.getCount();
		for(int i=0;i<count;i++){
			String category=data.getValue(i, series.getCategory());
			String item=data.getValue(i, series.getItem());
			String value=data.getValue(i, series.getValue());
			if(series.isIgnoreEmptyCategory() && StringUtils.isEmpty(category)){
				continue;
			}
			if(series.isIgnoreEmptyItem() && StringUtils.isEmpty(item)){
				continue;
			}
			if(series.isIgnoreEmptyValue() && StringUtils.isEmpty(value)){
				continue;
			}
			dataset.setValue(Double.valueOf(value), item, category);
		}
		JFreeChart chart=ChartFactory.createLineChart(null, series.getCategoryAxisLabel(),series.getValueAxisLabel(), dataset,series.isHorizontal()?PlotOrientation.HORIZONTAL:PlotOrientation.VERTICAL,series.isLegend(),false,false);
		chart.getRenderingHints().put (RenderingHints.KEY_TEXT_ANTIALIASING,series.isAntialias()?RenderingHints.VALUE_TEXT_ANTIALIAS_ON:RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
		chart.setBackgroundPaint(null);
		chart.setBorderPaint(null);
		if(series.isLegend()){
			chart.getLegend().setBackgroundPaint(Color.WHITE);
			switch (series.getLegendPosition()) {
			case 0:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			case 1:
				chart.getLegend().setPosition(RectangleEdge.RIGHT);
				break;
			case 2:
				chart.getLegend().setPosition(RectangleEdge.TOP);
				break;
			case 3:
				chart.getLegend().setPosition(RectangleEdge.LEFT);
				break;
			default:
				chart.getLegend().setPosition(RectangleEdge.BOTTOM);
				break;
			}
		}
		CategoryPlot plot = (CategoryPlot)chart.getPlot();
		plot.setNoDataMessage("<无数据>");
		plot.setBackgroundPaint(null);
		plot.setRangeGridlinePaint(Color.lightGray);
		plot.setRangeGridlinesVisible(series.isGridline());
		plot.setOutlineVisible(series.isOutline());
		LineAndShapeRenderer renderer = (LineAndShapeRenderer)plot.getRenderer();
		renderer.setBaseShapesVisible(series.isShape());
		renderer.setUseFillPaint(true);
		int seriesCount=dataset.getRowCount();
		for(int i=0;i<seriesCount;i++){
			renderer.setSeriesStroke(i, new BasicStroke(series.getLineWidth()));
			renderer.setSeriesOutlineStroke(i, new BasicStroke(series.getLineWidth()));
		}
		if(series.getColors()!=null && !series.getColors().isEmpty()){
			int colorcount=series.getColors().size();
			for(int i=0;i<seriesCount;i++){
				int colorindex=i%colorcount;
				renderer.setSeriesPaint(i, Color.decode(series.getColors().get(colorindex)));
			}
		}
		switch (series.getTickX()) {
		case 0:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
			break;
		case 1:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_45);
			break;
		case 2:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
			break;
		default:
			plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
			break;
		}
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		ChartUtilities.writeChartAsPNG(out, chart, width, height);
		return out.toByteArray();
	}

	public static byte[] generatePNG(ChartResultCell cell,int width,int height,Map<String, Serializable> params,Map<String, String> consts,Map<String,DataSetData> datas) throws Exception{
		byte[] png={};
		Series series=cell.getSeries();
		Map<String,Object> vars=new HashMap<String, Object>();
		vars.putAll(datas);
		vars.putAll(params);
		vars.put("CONSTS", consts);
		vars.put("ROW", cell.getRbegin()+1);
		vars.put("COL", cell.getCbegin()+1);
		vars.put("DATA", cell.getRecord());
		switch (series.getType()) {
			case Series.TYPE_CUSTOM:{
				png=generateCustom((CustomSeries)series, width, height, params,consts,cell.getRecord());
				break;
			}
			case Series.TYPE_NORMAL_BAR:{
				String code=((NormalBarSeries)series).getDataset();
				code=RenderUtil.renderString(code, vars);
				DataSetData data=datas.get(code);
				if(data==null){
					throw new Exception("未找到dataset["+code+"]");
				}
				png=generateNormalBarSeries((NormalBarSeries)series, width, height, data);
				break;
			}
			case Series.TYPE_NORMAL_LINE:{
				String code=((NormalLineSeries)series).getDataset();
				code=RenderUtil.renderString(code, vars);
				DataSetData data=datas.get(code);
				if(data==null){
					throw new Exception("未找到dataset["+code+"]");
				}
				png=generateNormalLineSeries((NormalLineSeries)series, width, height, data);
				break;
			}
			case Series.TYPE_NORMAL_PIE:{
				String code=((NormalPieSeries)series).getDataset();
				code=RenderUtil.renderString(code, vars);
				DataSetData data=datas.get(code);
				if(data==null){
					throw new Exception("未找到dataset["+code+"]");
				}
				png=generateNormalPieSeries((NormalPieSeries)series, width, height, data);
				break;
			}
			case Series.TYPE_STACK_BAR:{
				String code=((StackBarSeries)series).getDataset();
				code=RenderUtil.renderString(code, vars);
				DataSetData data=datas.get(code);
				if(data==null){
					throw new Exception("未找到dataset["+code+"]");
				}
				png=generateStackBarSeries((StackBarSeries)series, width, height, data);
				break;
			}
			case Series.TYPE_STACK_AREA:{
				String code=((StackAreaSeries)series).getDataset();
				code=RenderUtil.renderString(code, vars);
				DataSetData data=datas.get(code);
				if(data==null){
					throw new Exception("未找到dataset["+code+"]");
				}
				png=generateStackAreaSeries((StackAreaSeries)series, width, height, data);
				break;
			}
			case Series.TYPE_BAR_LINE:{
				String code=((BarLineSeries)series).getDataset();
				code=RenderUtil.renderString(code, vars);
				DataSetData data=datas.get(code);
				if(data==null){
					throw new Exception("未找到dataset["+code+"]");
				}
				png=generateBarLineSeries((BarLineSeries)series, width, height, data);
				break;
			}
			case Series.TYPE_MULTI_PIE:{
				String code=((MultiPieSeries)series).getDataset();
				code=RenderUtil.renderString(code, vars);
				DataSetData data=datas.get(code);
				if(data==null){
					throw new Exception("未找到dataset["+code+"]");
				}
				png=generateMultiPieSeries((MultiPieSeries)series, width, height, data);
				break;
			}
			case Series.TYPE_SPIDER_WEB:{
				String code=((SpiderWebSeries)series).getDataset();
				code=RenderUtil.renderString(code, vars);
				DataSetData data=datas.get(code);
				if(data==null){
					throw new Exception("未找到dataset["+code+"]");
				}
				png=generateSpiderWebSeries((SpiderWebSeries)series, width, height, data);
				break;
			}
			default:
				break;
		}
		return png;
	}
}
